/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define usart_rx_buf_len 128
#define UPDATE_HZ 100
#define USART_RX_TIMEOUT 10
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

void usart_put(uint8_t data);

gpio_struct GPIOSignals[] =
{
	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_4, 0}, //SEL1
	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_6, 0}, //SEL2
	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_0, 0}, //SEL3
	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_8, 1}, //SEL4

	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_2, 0}, //GRP1
	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_1, 0}, //GRP2
	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_7, 0}, //GRP3
	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_6, 0}, //GRP4

	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_5, 0}, //AUX1
	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_4, 0}, //AUX2
	{RCC_AHBPeriph_GPIOB, GPIOB, GPIO_Pin_3, 0}, //AUX3
	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_15, 0}, //AUX4

	{RCC_AHBPeriph_GPIOA, GPIOA, GPIO_Pin_11, 0} //USART_DIR
};

__IO uint8_t test_out = 0;
__IO uint32_t usart_overrun_counter = 0;
__IO uint8_t usart_data = 0;

__IO FIFOBuf usart_rx;
__IO uint8_t usart_rx_buf[usart_rx_buf_len];

__IO uint8_t usart_packet_buf[7];

__IO uint8_t USART_timeout_counter;

__IO uint8_t temperature;

uint16_t TS_CAL1, TS_CAL2, TS_DIFF;

/* Private function prototypes -----------------------------------------------*/
void TIM_Config(void);
void GPIO_Config(void);
void USART_Config(void);
void grp_aux_set(uint8_t data);
void pwm_set(uint8_t pwm_ch, uint8_t pwm_val);
void TempSensor_Config (void);
uint8_t Get_Temperature (void);
	
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured, 
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f30x.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f30x.c file
     */ 
  RCC_ClocksTypeDef RCC_Clocks;

  usart_rx.len = usart_rx_buf_len;
  usart_rx.buf = usart_rx_buf;
	
  GPIO_Config();
  TIM_Config();
  USART_Config();
  TempSensor_Config();
	
  /* SysTick end of count event each 1ms */
  RCC_GetClocksFreq(&RCC_Clocks);
  SysTick_Config(RCC_Clocks.HCLK_Frequency / UPDATE_HZ);
	
  USART_timeout_counter = 0;
  
  /* Infinite loop */
  while (1)
  {
		
		//while(j++ < 0xFF);
		
  //Delay(100);
    
  }
}

void scheduler (void)
{
	
	temperature = Get_Temperature();
	
	if (USART_timeout_counter < USART_RX_TIMEOUT)
	{
	  if (++USART_timeout_counter >= USART_RX_TIMEOUT)
	  {
	  	// If there is data timeout, disable all PWMs and groups
			pwm_set(1, 127);
			pwm_set(2, 127);
			pwm_set(3, 127);
			pwm_set(4, 127);

			GPIO_ResetBits(GPIOSignals[GRP1].GPIO_Port, GPIOSignals[GRP1].GPIO_Pin);
			GPIO_ResetBits(GPIOSignals[GRP2].GPIO_Port, GPIOSignals[GRP2].GPIO_Pin);
			GPIO_ResetBits(GPIOSignals[GRP3].GPIO_Port, GPIOSignals[GRP3].GPIO_Pin);
			GPIO_ResetBits(GPIOSignals[GRP4].GPIO_Port, GPIOSignals[GRP4].GPIO_Pin);
	  }
	}
}

static void GPIO_Config(void)
{
	uint8_t i;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	
	for (i = 0; i < COUNT_OF(GPIOSignals); i++)
	{
		/* GPIOx Periph clock enable */
		RCC_AHBPeriphClockCmd(GPIOSignals[i].RCC_AHBPeriph, ENABLE);
		GPIO_InitStructure.GPIO_Pin = GPIOSignals[i].GPIO_Pin;
		
		GPIO_Init(GPIOSignals[i].GPIO_Port, &GPIO_InitStructure);
		
		if (GPIOSignals[i].default_value == 1)
		{
			GPIO_SetBits(GPIOSignals[i].GPIO_Port, GPIOSignals[i].GPIO_Pin);
		}
		else
		{
			GPIO_ResetBits(GPIOSignals[i].GPIO_Port, GPIOSignals[i].GPIO_Pin);
		}
	}
	
}

static void TIM_Config(void)
{
	/*
		PWM1 - PA3 - TIM2_CH4 - AF2
		PWM2 - PA5 - TIM2_CH1 - AF2
		PWM3 - PA7 - TIM3_CH2 - AF1
		PWM4 - PB1 - TIM3_CH4 - AF1
	*/
	
  GPIO_InitTypeDef          GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
	TIM_OCInitTypeDef         TIM_OCInitStructure;
  
  /* TIM2 and TIM3 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  
  /* GPIOA and GPIOB clock enable*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
  
	GPIO_StructInit(&GPIO_InitStructure);
  /* Configure PA3, PA5, PA7 as Alternate Function*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
	/* Configure PB1 as Alternate Function*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
	
  /* Configure AF mux*/
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_2);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_2);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_1);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_1);


  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_OCStructInit(&TIM_OCInitStructure);

  /* Initialize Timers: TIM2, TIM3*/  
  /* Time base configuration for TIM2, TIM3 */
  TIM_TimeBaseStructure.TIM_Period = 127;
  TIM_TimeBaseStructure.TIM_Prescaler = 1260;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* Channel configuration on TIM2, TIM3*/
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 20;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
	
  TIM_OC4Init(TIM2, &TIM_OCInitStructure);
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  TIM_OC2Init(TIM3, &TIM_OCInitStructure);
  TIM_OC4Init(TIM3, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM2, ENABLE);
	TIM_ARRPreloadConfig(TIM3, ENABLE);
  
  /* TIM2 and TIM3 enable counter */
  TIM_Cmd(TIM2, ENABLE);
  TIM_Cmd(TIM3, ENABLE);
}

static void USART_Config(void)
{
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(USARTx_TX_GPIO_CLK | USARTx_RX_GPIO_CLK, ENABLE);
  
  /* Enable USART clock */
  USARTx_APBPERIPHCLOCK(USARTx_CLK, ENABLE);
  
	GPIO_StructInit(&GPIO_InitStructure);
  /* Configure USART Tx and Rx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN;
  GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
  GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin = USARTx_DIR_PIN;
  GPIO_Init(USARTx_DIR_GPIO_PORT, &GPIO_InitStructure);
	
  /* Connect PXx to USARTx_Tx */
  GPIO_PinAFConfig(USARTx_TX_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
	
  /* Connect PXx to USARTx_Rx */
  GPIO_PinAFConfig(USARTx_RX_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);

  /* USARTx configuration ----------------------------------------------------*/
  /* USARTx configured as follow:
  - BaudRate = 38400 baud  
  - Word Length = 8 Bits
  - One Stop Bit
  - No parity
  - Hardware flow control disabled (RTS and CTS signals)
  - Receive and transmit enabled
  */
	
  USART_StructInit(&USART_InitStructure);
	
  USART_InitStructure.USART_BaudRate = USART_BAUDRATE;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USARTx, &USART_InitStructure);
  
  /* NVIC configuration */
  /* Enable the USARTx Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
  USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
  USART_ITConfig(USARTx, USART_IT_ERR, ENABLE);
  
  /* Enable USART */
  USART_Cmd(USARTx, ENABLE);
}

void usart_put(uint8_t data)
{
	uint16_t i;
	
	for (i = 0; i < 6; i++)
	{
		usart_packet_buf[i] = usart_packet_buf[i+1];
	}
	usart_packet_buf[6] = data;
	
	if (usart_packet_buf[0] == 's')
	{
		if (crc8((unsigned char*)usart_packet_buf, 6) == usart_packet_buf[6])
		{
			// packet received
			pwm_set(1, usart_packet_buf[1]);
			pwm_set(2, usart_packet_buf[2]);
			pwm_set(3, usart_packet_buf[3]);
			pwm_set(4, usart_packet_buf[4]);
			
			grp_aux_set(usart_packet_buf[5]);

			// Clear timeout counter
			USART_timeout_counter = 0;

			/*// Wait some time
			i = 0xFF;
			while(--i != 0);
			// Enable RS485 DE
			GPIO_SetBits(USARTx_DIR_GPIO_PORT, USARTx_DIR_PIN);
			// Send a byte with temperature info
			USART_SendData(USARTx, Get_Temperature());
			// Wait until transmission is complete
			while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) != SET);
			// Wait some time
			i = 0xFF;
			while(--i != 0);
			// Disable RS485 DE
			GPIO_ResetBits(USARTx_DIR_GPIO_PORT, USARTx_DIR_PIN);*/
		}
	}
}

void grp_aux_set(uint8_t data)
{
	uint8_t group;
	
	// aux signals
	// aux 1
	if (data & 1)
		GPIO_SetBits(GPIOSignals[AUX1].GPIO_Port, GPIOSignals[AUX1].GPIO_Pin);
	else
		GPIO_ResetBits(GPIOSignals[AUX1].GPIO_Port, GPIOSignals[AUX1].GPIO_Pin);
	// aux 2
	if (data & 2)
		GPIO_SetBits(GPIOSignals[AUX2].GPIO_Port, GPIOSignals[AUX2].GPIO_Pin);
	else
		GPIO_ResetBits(GPIOSignals[AUX2].GPIO_Port, GPIOSignals[AUX2].GPIO_Pin);
	// aux 3
	if (data & 4)
		GPIO_SetBits(GPIOSignals[AUX3].GPIO_Port, GPIOSignals[AUX3].GPIO_Pin);
	else
		GPIO_ResetBits(GPIOSignals[AUX3].GPIO_Port, GPIOSignals[AUX3].GPIO_Pin);
	// aux 4
	if (data & 8)
		GPIO_SetBits(GPIOSignals[AUX4].GPIO_Port, GPIOSignals[AUX4].GPIO_Pin);
	else
		GPIO_ResetBits(GPIOSignals[AUX4].GPIO_Port, GPIOSignals[AUX4].GPIO_Pin);
	
	//group signals
	
	GPIO_ResetBits(GPIOSignals[GRP1].GPIO_Port, GPIOSignals[GRP1].GPIO_Pin);
	GPIO_ResetBits(GPIOSignals[GRP2].GPIO_Port, GPIOSignals[GRP2].GPIO_Pin);
	GPIO_ResetBits(GPIOSignals[GRP3].GPIO_Port, GPIOSignals[GRP3].GPIO_Pin);
	GPIO_ResetBits(GPIOSignals[GRP4].GPIO_Port, GPIOSignals[GRP4].GPIO_Pin);
	
	switch ((data >> 4) & 3)
	{
		case 1:
			group = GRP2;
			break;
		case 2:
			group = GRP3;
			break;
		case 3:
			group = GRP4;
			break;
		default:
			group = 0xFF;
	}
	
	if(group != 0xFF)
	{
		GPIO_SetBits(GPIOSignals[group].GPIO_Port, GPIOSignals[group].GPIO_Pin);
	}
	
	if (data & 0x40)
	{
		GPIO_SetBits(GPIOSignals[GRP1].GPIO_Port, GPIOSignals[GRP1].GPIO_Pin);
	}
}

void pwm_set(uint8_t pwm_ch, uint8_t pwm_val)
{
	uint8_t pwm_duty, pwm_pol, pwm_pol_pin;
	
	if(pwm_val >= 128)
	{
		pwm_pol = 1;
		pwm_duty = pwm_val - 128;
	}
	else
	{
		pwm_pol = 0;
		pwm_duty = 127 - pwm_val;
	}
	
	switch (pwm_ch)
	{
		case 1:
			pwm_pol_pin = SEL1;
			TIM_SetCompare4(TIM2, pwm_duty);
			break;
		case 2:
			pwm_pol_pin = SEL2;
			TIM_SetCompare1(TIM2, pwm_duty);
			break;
		case 3:
			pwm_pol_pin = SEL3;
			TIM_SetCompare2(TIM3, pwm_duty);
			break;
		case 4:
			pwm_pol_pin = SEL4;
			TIM_SetCompare4(TIM3, pwm_duty);
			break;
	}
	if (pwm_pol == 1)
	{
		GPIO_SetBits(GPIOSignals[pwm_pol_pin].GPIO_Port, GPIOSignals[pwm_pol_pin].GPIO_Pin);
	}
	if (pwm_pol == 0)
	{
		GPIO_ResetBits(GPIOSignals[pwm_pol_pin].GPIO_Port, GPIOSignals[pwm_pol_pin].GPIO_Pin);
	}
}

void TempSensor_Config (void)
{
	TS_CAL1 = *((uint16_t*) 0x1FFFF7B8);
	TS_CAL2 = *((uint16_t*) 0x1FFFF7C2);
	TS_DIFF = TS_CAL2 - TS_CAL1;

  	ADC_Config();
}

uint8_t Get_Temperature (void)
{
	int32_t TempSensorReadout = ADC_GetConversionValue(ADC1);

	return (((TempSensorReadout - TS_CAL1) * 80) / TS_DIFF) + 30;
}
